﻿using Aurora.AI.Abstractions;
using Aurora.AI.Abstractions.Chats;
using Aurora.AI.Abstractions.Chats.Dtos;
using Aurora.AI.Abstractions.Dtos;
using Aurora.AI.MetaGLM.Models.RequestModels;
using Aurora.AI.MetaGLM.Models.RequestModels.FunctionModels;
using System.Runtime.CompilerServices;
using System.Text.Json;
using System.Text.RegularExpressions;
using Aurora.AI.Common.Extensions;
using Aurora.AI.MetaGLM.Models.RequestModels.ImageToTextModels;
using Aurora.AI.MetaGLM.Models.RequestModels.WebSearchModels;
using Aurora.AI.MetaGLM.Models.ResponseModels.ToolModels;
using Microsoft.Extensions.Logging;

namespace Aurora.AI.MetaGLM.Chats;

/// <summary>
/// meta glm 对话 （智谱清言）
/// </summary>
public sealed class MetaGLMChatCompletionsService : IAuroraAIChatCompletionsService
{
    private readonly MetaGLMPlatformOptions _openAiOptions;
    private readonly ILogger<MetaGLMChatCompletionsService> _logger;

    public MetaGLMChatCompletionsService(ILogger<MetaGLMChatCompletionsService> logger)
    {
        _logger = logger;
        _openAiOptions = new MetaGLMPlatformOptions
        {
            Client = new MetaGLMClientV4()
        };
    }

    public async Task<AuroraAIChatCompletionsResponse> ChatCompletionsAsync(AuroraAIChatCompletionsRequest input,
        AuroraAIPlatformOptions options = null,
        CancellationToken cancellationToken = default)
    {
        var dto = new TextRequestBase();
        dto.request_id = Guid.NewGuid().ToString();
        // 需要识别 content 中 是否是 一个对象
        dto.messages.AddRange(input.Messages.Select(x => new MessageItem
        {
            content = x.Content == null ? x.Contents : x.Content,
            role = x.Role.ToString()
        }).ToList());

        dto.model = input.Model;

        if (input.Temperature.HasValue)
        {
            dto.temperature = input.Temperature.Value;
        }

        if (input.TopP.HasValue)
        {
            dto.top_p = input.TopP.Value;
        }

        // // 判断是否有 web_search
        // if (input.WebSearchs != null)
        // {
        //     // 往 dto.tools 追加
        //     foreach (var webSearch in input.WebSearchs)
        //     {
        //         dto.tools.Add(new WebSearchTool()
        //         {
        //             Enable = webSearch.Enable,
        //             SearchQuery = webSearch.SearchQuery,
        //             SearchPrompt = webSearch.SearchPrompt,
        //             SearchResult = webSearch.SearchResult
        //         });
        //     }
        // }

        if (input.Tools != null)
        {
            foreach (var tool in input.Tools)
            {
                var functions = new FunctionTool
                {
                    type = tool.Type
                };
                if (!string.IsNullOrEmpty(tool.Function?.Name))
                    functions.SetName(tool.Function.Name);

                if (!string.IsNullOrEmpty(tool.Function?.Description))
                    functions.SetDescription(tool.Function.Description);

                var function = new FunctionParameters()
                {
                    required = tool.Function?.Parameters?.Required?.ToArray(),
                    type = tool.Function?.Parameters?.Type,
                };

                if (tool.Function?.Parameters?.Properties != null)
                {
                    foreach (var definition in tool.Function.Parameters.Properties)
                    {
                        function.properties.Add(definition.Key,
                            new FunctionParameterDescriptor(definition.Value.Type, definition.Value.Description));
                    }
                }

                functions.SetParameters(function);

                dto.tools.Add(functions);
            }
        }

        var result = await _openAiOptions.Client?.Chat.Completion(dto, options.ApiKey, options.Address);

        // 打印信息
        _logger.LogInformation("【Glm-Chat】响应信息：" + AuroraAIJsonSerializer.Serialize(result));
        if (result.error != null)
        {
            throw new Exception($"code:{result.error["code"]},message:{result.error["message"]}");
        }

        var tools = new List<AuroraAIToolCall>();
        foreach (var choiceItem in result.choices)
        {
            if (choiceItem.message.tool_calls == null)
            {
                continue;
            }

            tools.AddRange(choiceItem.message?.tool_calls?.Select(x => new AuroraAIToolCall()
            {
                Id = x.id,
                Type = x.type,
                Function = new AuroraAIChatMessageFunction()
                {
                    Arguments = x.function?.arguments,
                    Name = x.function?.name,
                }
            }));
        }

        var message =
            AuroraAIChatMessage.CreateAssistantMessage(result.choices.FirstOrDefault()?.message.content ?? string.Empty,
                null, tools);

        return new AuroraAIChatCompletionsResponse()
        {
            Choices =
            [
                new()
                {
                    Delta = message,
                    Message = message,
                    FinishReason = "stop",
                    Index = 0,
                }
            ],
            Error = new AuroraAIError
            {
                MessageObject = result.error?.FirstOrDefault().Value ?? string.Empty,
            },
            Model = input.Model
        };
    }

    public async IAsyncEnumerable<AuroraAIChatCompletionsResponse> StreamChatCompletionsAsync(
        AuroraAIChatCompletionsRequest input,
        AuroraAIPlatformOptions options = null,
        [EnumeratorCancellation] CancellationToken cancellationToken = default)
    {
        var dto = new TextRequestBase();
        dto.request_id = Guid.NewGuid().ToString();
        dto.messages.AddRange(input.Messages.Select(x => new MessageItem
        {
            content = x.Content == null ? x.Contents : x.Content,
            role = x.Role.ToString()
        }).ToList());

        dto.model = input.Model!;

        if (input.Temperature.HasValue)
        {
            dto.temperature = input.Temperature.Value;
        }

        if (input.TopP.HasValue)
        {
            dto.top_p = input.TopP.Value;
        }

        // 判断是否有 web_search
        if (input.WebSearch != null)
        {
            // 往 dto.tools 追加
            dto.tools.Add(new
            {
                type="web_search",
                web_search= new 
                {
                    enable = input.WebSearch.Enable,
                    // SearchQuery = input.WebSearch.SearchQuery,
                    // SearchPrompt = input.WebSearch.SearchPrompt,
                    search_result = input.WebSearch.SearchResult
                }
            } );
        }
        // dto.tools.Add(new
        // {
        //     type="web_search",
        //     web_search=new
        //     {
        //         enable = input.WebSearch.Enable,
        //         search_result = input.WebSearch.SearchResult
        //     }
        // });

        // dto.type = "web_search";
        if (input.Tools != null)
        {
            foreach (var tool in input.Tools)
            {
                var functions = new FunctionTool
                {
                    type = tool.Type
                };
                if (!string.IsNullOrEmpty(tool.Function?.Name))
                    functions.SetName(tool.Function.Name);

                if (!string.IsNullOrEmpty(tool.Function?.Description))
                    functions.SetDescription(tool.Function.Description);

                var function = new FunctionParameters()
                {
                    required = tool.Function?.Parameters?.Required?.ToArray() ?? [],
                    type = tool.Function?.Parameters?.Type ?? string.Empty,
                };

                if (tool.Function?.Parameters?.Properties != null)
                {
                    foreach (var definition in tool.Function.Parameters.Properties)
                    {
                        function.properties.Add(definition.Key,
                            new FunctionParameterDescriptor(definition.Value.Type,
                                definition.Value?.Description ?? string.Empty));
                    }
                }

                functions.SetParameters(function);

                dto.tools.Add(functions);
            }
        }

        // 启用 web_search

        await foreach (var result in _openAiOptions.Client?.Chat.Stream(dto, options.ApiKey, options.Address))
        {
            var tools = new List<AuroraAIToolCall>();

            foreach (var choiceItem in result.choices)
            {
                if (choiceItem.delta.tool_calls is null)
                {
                    continue;
                }

                tools.AddRange(choiceItem.delta.tool_calls.Select(x => new AuroraAIToolCall()
                {
                    Id = x.id,
                    Type = x.type,
                    Function = new AuroraAIChatMessageFunction()
                    {
                        Arguments = x.function.arguments,
                        Name = x.function.name,
                    }
                }));
            }

            List<AuroraAIWebSearchTooItem> webSearches = null;
            if (result.web_search is not null)
            {
                webSearches = new List<AuroraAIWebSearchTooItem>();
                foreach (WebSearchItem webSearchItem in result.web_search)
                {
                    AuroraAIWebSearchTooItem item = new AuroraAIWebSearchTooItem()
                    {
                        content = webSearchItem.content,
                        icon = webSearchItem.icon,
                        link = webSearchItem.link,
                        media = webSearchItem.media,
                        title = webSearchItem.title,
                    };
                    webSearches.Add(item);
                }
            }

            var message =
                AuroraAIChatMessage.CreateAssistantMessage(
                    result.choices.FirstOrDefault()?.delta.content ?? string.Empty, toolCalls: tools,
                    webSearch: webSearches);
            yield return new AuroraAIChatCompletionsResponse()
            {
                Choices =
                [
                    new()
                    {
                        Delta = message,
                        Message = message,
                        FinishReason = "stop",
                        Index = 0,
                    }
                ],
                Model = input.Model
            };
        }
    }
}